#ifndef MATRIZABASTRACTA_H_
#define MATRIZABASTRACTA_H_
#include <iostream>

typedef unsigned int Uint;
typedef Uint Indice;
typedef Uint Tam;

using namespace std;

/**
 * Clase base para las matrices.
 * La idea es que los algoritmos utilicen MatrizAbstracta 
 * para abstraerse de cualquier implementación posterior.
 */
class MatrizAbstracta {
	public :
        /**
		 * Devuelve el valor de la matriz en la posición indicada.
		 * @param i Fila i-esima de la matriz.
		 * @param j Columna j-esima de la matriz.
		 * @return El valor de la matriz en la fila i y la columna j.
		 * @remarks Los indices comienzan desde uno.
		 */
		virtual double get(Indice fila, Indice columna) const = 0;

        /**
		 * Establece el valor de la matriz en la posición indicada.
		 * @param i Fila i-esima de la matriz.
		 * @param j Columna j-esima de la matriz.
		 * @param valor El nuevo valor de la matriz en la fila i y la columna j.
		 * @remarks Los indices comienzan desde uno. Además notar que no es 
		 * virtual PURA, esto es debido a que las matrices derivadas tal vez no necesiten
		 * implementar el método set, es decir serían una especie de matriz de
		 * solo lectura.
		 */
		virtual void set(Indice fila, Indice columna, double valor);

		/**
		 * Devuelve la cantidad de filas de la matriz.
		 */
		virtual Tam cantidadDeFilas() const = 0;

		/**
		 * Devuelve la cantidad de columnas de la matriz.
		 */
		virtual Tam cantidadDeColumnas() const = 0;
		
		//virtual void copiarMatriz(const MatrizAbstracta* m);

		/**
		 * Método abreviado para la operación get.
		 * Si bien en C++ los paréntesis se utilizan para llamadas a función,
		 * cambiarle la semántica para que devuelva el valor en la posición Mij
		 * no presenta un cambio dramático, ya que en matemáticas esta
		 * notación es habitual.
		 * No se utilizo la sobrecarga del operador [], por que no puede recibir
		 * dos parámetros.
		 * @see get
		 */
		double operator()(Indice i, Indice j) const;

		/**
		 * Suma a la fila filaDestino un multiplo (factor) de la filaOrigen.
		 * Esta operación es una operación entre filas de la matriz y se
		 * utliza para factorizarla.
		 * @param filaOrigen Fila origen de la matriz.
		 * @param filaDestino Fila destino de la matriz.
		 * @param factor Factor para multiplicar a la fila filaOrigen.
		 */
		void sumaMultiplo(
			Indice filaOrigen,
			Indice filaDestino,
			double factor,
			Indice columnaDesde,
			Indice columnaHasta
		);

		/**
		 * Sobrecarga de sumaMultiplo, donde columnaDesde = 1 y
		 * columnaHasta = cantidadDeColumnas()
		 * @param filaOrigen Fila origen de la matriz.
		 * @param filaDestino Fila destino de la matriz.
		 * @param factor Factor para multiplicar a la fila filaOrigen.
		 */
		void sumaMultiplo(
			Indice filaOrigen,
			Indice filaDestino,
			double factor
		);

		/**
		 * Serialización de la matriz. 
		 * El formato utilizado es de Matlab.
		 */
		ostream& serializate(ostream& o, bool conFormatoMatlab = true) const;

		/**
		 * Sobrecarga del operador <<.
		 */
		friend ostream& operator<<(ostream& o, const MatrizAbstracta& m);
};

#endif /*MATRIZABASTRACTA_H_*/
